home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
016a
/
gofer221.zip
/
BUILTIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-20
|
39KB
|
1,252 lines
/* --------------------------------------------------------------------------
* builtin.c: Copyright (c) Mark P Jones 1991. All rights reserved.
* See goferite.h for details and conditions of use etc...
* Gofer version 2.21 November 1991
*
* Last updated 03/11/91 mpj
*
* Primitive functions, input output etc...
* ------------------------------------------------------------------------*/
#include "prelude.h"
#include "storage.h"
#include "connect.h"
#include "errors.h"
#include <ctype.h>
#if TURBOC
#include <io.h>
#endif
Name nameFatbar, nameFail; /* primitives reqd for translation */
Name nameIf, nameSel;
Name nameMinus, nameDivide;
Name nameUndefMem; /* undefined member primitive */
Name nameError; /* error primitive function */
Name nameAnd, nameOr; /* built-in logical connectives */
Name namePrint, nameNPrint; /* primitives for printing */
static Name nameLPrint, nameNLPrint; /* list printing primitives */
static Name nameSPrint, nameNSPrint; /* string printing primitives */
static Name nameInput; /* For reading from stdin */
/* --------------------------------------------------------------------------
* Local function prototypes:
* ------------------------------------------------------------------------*/
#define PROTO_PRIM(name) static Void name Args((StackPtr))
#define primFun(name) static Void name(root) StackPtr root;
#define primArg(n) stack(root+n)
#define update(l,r) ((fst(stack(root))=l),(snd(stack(root))=r))
#define updateRoot(c) update(INDIRECT,c)
#define updapRoot(l,r) update(l,r)
#define cantReduce() evalFails(root)
PROTO_PRIM(primFatbar);
PROTO_PRIM(primFail);
PROTO_PRIM(primUndefMem);
PROTO_PRIM(primSel);
PROTO_PRIM(primIf);
PROTO_PRIM(primStrict);
PROTO_PRIM(primPlusInt);
PROTO_PRIM(primMinusInt);
PROTO_PRIM(primMulInt);
PROTO_PRIM(primDivInt);
PROTO_PRIM(primModInt);
PROTO_PRIM(primRemInt);
PROTO_PRIM(primNegInt);
PROTO_PRIM(primCharToInt);
PROTO_PRIM(primIntToChar);
PROTO_PRIM(primIntToFloat);
PROTO_PRIM(primPlusFloat);
PROTO_PRIM(primMinusFloat);
PROTO_PRIM(primMulFloat);
PROTO_PRIM(primDivFloat);
PROTO_PRIM(primNegFloat);
PROTO_PRIM(primEqInt);
PROTO_PRIM(primLeInt);
PROTO_PRIM(primEqFloat);
PROTO_PRIM(primLeFloat);
PROTO_PRIM(primCmp);
PROTO_PRIM(primGenericEq);
PROTO_PRIM(primGenericLe);
PROTO_PRIM(primGenericLt);
PROTO_PRIM(primGenericGe);
PROTO_PRIM(primGenericGt);
PROTO_PRIM(primGenericNe);
PROTO_PRIM(primPrint);
PROTO_PRIM(primNPrint);
static Void local printer Args((StackPtr,Name,Int,Cell));
static Void local startList Args((StackPtr,Cell));
static Void local startNList Args((StackPtr,Cell));
PROTO_PRIM(primLPrint);
PROTO_PRIM(primNLPrint);
PROTO_PRIM(primSPrint);
PROTO_PRIM(primNSPrint);
static Cell local textAsVar Args((Text,Cell));
static Cell local textAsOp Args((Text,Cell));
static Cell local stringOutput Args((String,Cell));
static Cell local printBadRedex Args((Cell,Cell));
static String local evalName Args((Cell));
static Void local abandonDialogue Args((Cell));
static Cell local printDBadRedex Args((Cell,Cell));
static Cell local readFile Args((Void));
static Cell local writeFile Args((Void));
static Cell local appendFile Args((Void));
static Cell local readChan Args((Void));
static Cell local appendChan Args((Void));
static FILE *local validOutChannel Args((String));
static Cell local echo Args((Void));
PROTO_PRIM(primInput);
/* --------------------------------------------------------------------------
* Table of primitive/built-in values:
* ------------------------------------------------------------------------*/
struct primitive primitives[] = {
{"primPlusInt", 2, primPlusInt}, {"primMinusInt", 2, primMinusInt},
{"primMulInt", 2, primMulInt}, {"primDivInt", 2, primDivInt},
{"primModInt", 2, primModInt}, {"primRemInt", 2, primRemInt},
{"primNegInt", 1, primNegInt},
{"primPlusFloat",2, primPlusFloat}, {"primMinusFloat",2, primMinusFloat},
{"primMulFloat", 2, primMulFloat}, {"primDivFloat", 2, primDivFloat},
{"primNegFloat", 1, primNegFloat},
{"primIntToChar",1, primIntToChar}, {"primCharToInt", 1, primCharToInt},
{"primIntToFloat",1,primIntToFloat},
{"primEqInt", 2, primEqInt}, {"primLeInt", 2, primLeInt},
{"primEqFloat", 2, primEqFloat}, {"primLeFloat", 2, primLeFloat},
{"primGenericEq",2, primGenericEq}, {"primGenericNe", 2, primGenericNe},
{"primGenericGt",2, primGenericGt}, {"primGenericLe", 2, primGenericLe},
{"primGenericGe",2, primGenericGe}, {"primGenericLt", 2, primGenericLt},
{"primPrint", 3, primPrint},
{"primStrict", 2, primStrict},
{0, 0, 0}
};
/* --------------------------------------------------------------------------
* Primitive functions:
* ------------------------------------------------------------------------*/
primFun(primFatbar) { /* Fatbar primitive */
Cell l = primArg(2); /* _FAIL [] r = r */
Cell r = primArg(1); /* l [] r = l -- otherwise */
Cell temp = evalWithNoError(l);
if (nonNull(temp))
if (temp==nameFail)
updateRoot(r);
else {
updateRoot(temp);
cantReduce();
}
else
updateRoot(l);
}
primFun(primFail) { /* Failure primitive */
cantReduce();
}
primFun(primUndefMem) { /* undefined member function */
cantReduce();
}
primFun(primSel) { /* Component selection */
Cell c = primArg(3); /* _sel c e n return nth component*/
Cell e = primArg(2); /* in expression e */
Cell n = intOf(primArg(1)); /* built using cfun c */
eval(e);
if (whnfHead==c && ((isName(whnfHead) && name(whnfHead).arity==whnfArgs)
|| (isTuple(whnfHead) && tupleOf(whnfHead)==whnfArgs)))
updateRoot(pushed(n-1));
else
cantReduce();
}
primFun(primIf) { /* Conditional primitive */
eval(primArg(3));
if (whnfHead==nameTrue)
updateRoot(primArg(2));
else
updateRoot(primArg(1));
}
primFun(primStrict) { /* Strict application primitive */
eval(primArg(1)); /* evaluate 2nd argument */
updapRoot(primArg(2),primArg(1)); /* and apply 1st argument to result */
}
/* --------------------------------------------------------------------------
* Integer arithmetic primitives:
* ------------------------------------------------------------------------*/
primFun(primPlusInt) { /* Integer addition primitive */
Int x;
eval(primArg(2));
x = whnfInt;
eval(primArg(1));
updateRoot(mkInt(x+whnfInt));
}
primFun(primMinusInt) { /* Integer subtraction primitive */
Int x;
eval(primArg(2));
x = whnfInt;
eval(primArg(1));
updateRoot(mkInt(x-whnfInt));
}
primFun(primMulInt) { /* Integer multiplication primitive */
Int x;
eval(primArg(2));
x = whnfInt;
eval(primArg(1));
updateRoot(mkInt(x*whnfInt));
}
primFun(primDivInt) { /* Integer division primitive */
Int x;
eval(primArg(2));
x = whnfInt;
eval(primArg(1));
if (whnfInt==0)
cantReduce();
updateRoot(mkInt(x/whnfInt));
}
primFun(primModInt) { /* Integer modulo primitive */
Int x,y;
eval(primArg(2));
x = whnfInt;
eval(primArg(1));
if (whnfInt==0)
cantReduce();
y = x%whnfInt; /* "... the modulo having the sign */
if ((x<0 && whnfInt>0) || /* of the divisor ..." */
(x>0 && whnfInt<0)) /* See definition on p.81 of Haskell*/
updateRoot(mkInt(y+whnfInt)); /* report... */
else
updateRoot(mkInt(y));
}
primFun(primRemInt) { /* Integer remainder primitive */
Int x;
eval(primArg(2)); /* div and rem satisfy: */
x = whnfInt; /* (x `div` y)*y + (x `rem` y) == x */
eval(primArg(1)); /* which is exactly the property */
if (whnfInt==0) /* described in K&R 2: */
cantReduce(); /* (a/b)*b + a%b == a */
updateRoot(mkInt(x%whnfInt));
}
primFun(primNegInt) { /* Integer negation primitive */
eval(primArg(1));
updateRoot(mkInt(-whnfInt));
}
/* --------------------------------------------------------------------------
* Coercion primitives:
* ------------------------------------------------------------------------*/
primFun(primCharToInt) { /* Character to integer primitive */
eval(primArg(1));
updateRoot(mkInt(charOf(whnfHead)));
}
primFun(primIntToChar) { /* Integer to character primitive */
eval(primArg(1));
if (whnfInt<0 || whnfInt>MAXCHARVAL)
cantReduce();
updateRoot(mkChar(whnfInt));
}
primFun(primIntToFloat) { /* Integer to Float primitive */
eval(primArg(1));
updateRoot(mkFloat((Float)(whnfInt)));
}
/* --------------------------------------------------------------------------
* Float arithmetic primitives:
* ------------------------------------------------------------------------*/
primFun(primPlusFloat) { /* Float addition primitive */
Float x;
eval(primArg(2));
x = whnfFloat;
eval(primArg(1));
updateRoot(mkFloat(x+whnfFloat));
}
primFun(primMinusFloat) { /* Float subtraction primitive */
Float x;
eval(primArg(2));
x = whnfFloat;
eval(primArg(1));
updateRoot(mkFloat(x-whnfFloat));
}
primFun(primMulFloat) { /* Float multiplication primitive */
Float x;
eval(primArg(2));
x = whnfFloat;
eval(primArg(1));
updateRoot(mkFloat(x*whnfFloat));
}
primFun(primDivFloat) { /* Float division primitive */
Float x;
eval(primArg(2));
x = whnfFloat;
eval(primArg(1));
if (whnfFloat==0)
cantReduce();
updateRoot(mkFloat(x/whnfFloat));
}
primFun(primNegFloat) { /* Float negation primitive */
eval(primArg(1));
updateRoot(mkFloat(-whnfFloat));
}
/* --------------------------------------------------------------------------
* Comparison primitives:
* ------------------------------------------------------------------------*/
primFun(primEqInt) { /* Integer equality primitive */
Int x;
eval(primArg(2));
x = whnfInt;
eval(primArg(1));
updateRoot(x==whnfInt ? nameTrue : nameFalse);
}
primFun(primLeInt) { /* Integer <= primitive */
Int x;
eval(primArg(2));
x = whnfInt;
eval(primArg(1));
updateRoot(x<=whnfInt ? nameTrue : nameFalse);
}
primFun(primEqFloat) { /* Float equality primitive */
Float x;
eval(primArg(2));
x = whnfFloat;
eval(primArg(1));
updateRoot(x==whnfFloat ? nameTrue : nameFalse);
}
primFun(primLeFloat) { /* Float <= primitive */
Float x;
eval(primArg(2));
x = whnfFloat;
eval(primArg(1));
updateRoot(x<=whnfFloat ? nameTrue : nameFalse);
}
/* Generic comparisons implemented using the internal primitive function:
*
* primCmp [] = EQ
* ((C xs, D ys):rs)
* | C < D = LT
* | C == D = primCmp (zip xs ys ++ rs)
* | C > D = GT
* ((Int n, Int m):rs)
* | n < m = LT
* | n == m = primCmp rs
* | n > m = GT
* etc ... similar for comparison of characters:
*
* The list argument to primCmp is represented as an `internal list';
* i.e. no (:)/[] constructors - use internal cons and NIL instead!
*
* To compare two values x and y, evaluate primCmp [(x,y)] and use result.
*/
#define LT 1
#define EQ 2
#define GT 3
#define compResult(x) updateRoot(mkInt(x))
static Name namePrimCmp;
primFun(primCmp) { /* generic comparison function */
Cell rs = primArg(1);
if (isNull(rs)) {
compResult(EQ);
return;
}
else {
Cell x = fst(hd(rs));
Cell y = snd(hd(rs));
Int whnfArgs1;
Cell whnfHead1;
rs = tl(rs);
eval(x);
whnfArgs1 = whnfArgs;
whnfHead1 = whnfHead;
switch (whatIs(whnfHead1)) {
case INTCELL : if (whnfArgs==0) { /* compare ints */
eval(y);
if (!isInt(whnfHead) || whnfArgs!=0)
break;
if (intOf(whnfHead1) > whnfInt)
compResult(GT);
else if (intOf(whnfHead1) < whnfInt)
compResult(LT);
else
updapRoot(namePrimCmp,rs);
return;
}
case FLOATCELL: if (whnfArgs==0) { /* compare floats */
eval(y);
if (!isFloat(whnfHead) || whnfArgs!=0)
break;
if (floatOf(whnfHead1) > whnfFloat)
compResult(GT);
else if (floatOf(whnfHead1) < whnfFloat)
compResult(LT);
else
updapRoot(namePrimCmp,rs);
return;
}
break;
case CHARCELL : if (whnfArgs==0) { /* compare chars */
eval(y);
if (!isChar(whnfHead) || whnfArgs!=0)
break;
if (charOf(whnfHead1) > charOf(whnfHead))
compResult(GT);
else if (charOf(whnfHead1) < charOf(whnfHead))
compResult(LT);
else
updapRoot(namePrimCmp,rs);
return;
}
break;
default : eval(y); /* compare structs */
if (whnfHead1==whnfHead &&
whnfArgs1==whnfArgs &&
(whnfHead==UNIT ||
isTuple(whnfHead) ||
(isName(whnfHead) &&
name(whnfHead).defn==CFUN))) {
while (whnfArgs1-- >0)
rs = cons(pair(pushed(whnfArgs+whnfArgs1),
pushed(whnfArgs1)),rs);
updapRoot(namePrimCmp,rs);
return;
}
if (isName(whnfHead1) &&
name(whnfHead1).defn==CFUN &&
isName(whnfHead) &&
name(whnfHead).defn==CFUN) {
if (name(whnfHead1).number
> name(whnfHead).number)
compResult(GT);
else if (name(whnfHead1).number
< name(whnfHead).number)
compResult(LT);
else
break;
return;
}
break;
}
/* we're going to fail because we can't compare x and y; modify */
/* the root expression so that it looks reasonable before failing */
/* i.e. output produced will be: {_compare x y} */
updapRoot(ap(namePrimCmp,x),y);
}
cantReduce();
}
primFun(primGenericEq) { /* Generic equality test */
Cell c = ap(namePrimCmp,singleton(pair(primArg(2),primArg(1))));
eval(c);
updateRoot(whnfInt==EQ ? nameTrue : nameFalse);
}
primFun(primGenericLe) { /* Generic <= test */
Cell c = ap(namePrimCmp,singleton(pair(primArg(2),primArg(1))));
eval(c);
updateRoot(whnfInt<=EQ ? nameTrue : nameFalse);
}
primFun(primGenericLt) { /* Generic < test */
Cell c = ap(namePrimCmp,singleton(pair(primArg(2),primArg(1))));
eval(c);
updateRoot(whnfInt<EQ ? nameTrue : nameFalse);
}
primFun(primGenericGe) { /* Generic >= test */
Cell c = ap(namePrimCmp,singleton(pair(primArg(2),primArg(1))));
eval(c);
updateRoot(whnfInt>=EQ ? nameTrue : nameFalse);
}
primFun(primGenericGt) { /* Generic > test */
Cell c = ap(namePrimCmp,singleton(pair(primArg(2),primArg(1))));
eval(c);
updateRoot(whnfInt>EQ ? nameTrue : nameFalse);
}
primFun(primGenericNe) { /* Generic /= test */
Cell c = ap(namePrimCmp,singleton(pair(primArg(2),primArg(1))));
eval(c);
updateRoot(whnfInt!=EQ ? nameTrue : nameFalse);
}
/* --------------------------------------------------------------------------
* Print primitives:
* ------------------------------------------------------------------------*/
static Cell consOpen, consSpace, consComma, consClose;
static Cell consObrace, consCbrace, consOsq, consCsq;
static Cell consBack, consMinus, consQuote, consDQuote;
#define print(pr,d,e,ss) ap(ap(ap(pr,mkInt(d)),e),ss)
#define lprint(pr,xs,ss) ap(ap(pr,xs),ss)
#define printString(s,ss) revOnto(stringOutput(s,NIL),ss)
#define printSChar(c,ss) printString(unlexChar(c,'\"'),ss)
primFun(primPrint) { /* evaluate and print term */
Int d = intOf(primArg(3)); /* :: Int->Expr->[Char]->[Char] */
Cell e = primArg(2);
Cell ss = primArg(1);
Cell temp = evalWithNoError(e);
if (nonNull(temp))
updateRoot(printBadRedex(temp,ss));
else
printer(root,namePrint,d,ss);
}
primFun(primNPrint) { /* print term without evaluation */
Int d = intOf(primArg(3)); /* :: Int->Expr->[Char]->[Char] */
Cell e = primArg(2);
Cell ss = primArg(1);
unwind(e);
printer(root,nameNPrint,d,ss);
}
static Void local printer(root,pr,d,ss) /* Main part: primPrint/primNPrint */
StackPtr root; /* root or print redex */
Name pr; /* printer to use on components */
Int d; /* precedence level */
Cell ss; { /* rest of output */
Int used = 0;
Cell output = NIL;
switch(whatIs(whnfHead)) {
case NAME : { Syntax sy = syntaxOf(name(whnfHead).text);
if (name(whnfHead).defn!=CFUN ||
name(whnfHead).arity>whnfArgs)
pr = nameNPrint;
if (whnfHead==nameCons && whnfArgs==2) {/*list */
if (pr==namePrint)
startList(root,ss);
else
startNList(root,ss);
return;
}
if (whnfArgs==1 && sy!=APPLIC) { /* (e1+) */
used = 1;
output = ap(consClose,
textAsOp(name(whnfHead).text,
ap(consSpace,
print(pr,FUN_PREC-1,pushed(0),
ap(consOpen,NIL)))));
}
else if (whnfArgs>=2 && sy!=APPLIC) { /* e1+e2 */
Syntax a = assocOf(sy);
Int p = precOf(sy);
used = 2;
if (whnfArgs>2 || d>p)
output = ap(consOpen,output);
output = print(pr,(a==RIGHT_ASS?p:1+p),
pushed(1),
ap(consSpace,
textAsOp(name(whnfHead).text,
ap(consSpace,
print(pr,(a==LEFT_ASS? p:1+p),
pushed(0),
output)))));
if (whnfArgs>2 || d>p)
output = ap(consClose,output);
}
else /* f ... */
output = textAsVar(name(whnfHead).text,NIL);
}
break;
case INTCELL : { Int digit;
if (intOf(whnfHead)<0 && d>=FUN_PREC)
output = ap(consClose,output);
do {
digit = whnfInt%10;
if (digit<0)
digit= (-digit);
output = ap(consChar('0'+digit),output);
} while ((whnfInt/=10)!=0);
if (intOf(whnfHead)<0) {
output = ap(consMinus,output);
if (d>=FUN_PREC)
output = ap(consOpen,output);
}
output = rev(output);
pr = nameNPrint;
}
break;
case UNIT : output = ap(consClose,ap(consOpen,NIL));
pr = nameNPrint;
break;
case TUPLE : { Int tn = tupleOf(whnfHead);
Cell punc = consOpen;
Int i;
used = tn<whnfArgs ? tn : whnfArgs;
output = NIL;
for (i=0; i<used; ++i) {
output = print(pr,MIN_PREC,pushed(i),
ap(punc,
output));
punc = consComma;
}
for (; i<tn; ++i) {
output = ap(punc,output);
punc = consComma;
}
output = ap(consClose,output);
}
pr = nameNPrint;
break;
case CHARCELL : output = ap(consQuote,
stringOutput(unlexChar(charOf(whnfHead),
'\''),
ap(consQuote,
output)));
pr = nameNPrint;
break;
case FLOATCELL: output = stringOutput(floatToString(whnfFloat),
output);
pr = nameNPrint;
break;
case DICTCELL : output = stringOutput("{dict}",output);
pr = nameNPrint;
break;
case FILECELL : output = stringOutput("{file}",output);
pr = nameNPrint;
break;
default : internal("Error in graph");
break;
}
if (used<whnfArgs) { /* Add remaining args to output */
do
output = print(pr,FUN_PREC,pushed(used),ap(consSpace,output));
while (++used<whnfArgs);
if (d>=FUN_PREC) { /* Determine if parens are needed */
updapRoot(consOpen,revOnto(output,ap(consClose,ss)));
return;
}
}
updateRoot(revOnto(output,ss));
}
/* --------------------------------------------------------------------------
* List printing primitives:
* ------------------------------------------------------------------------*/
static Void local startList(root,ss) /* start printing evaluated list */
StackPtr root;
Cell ss; {
Cell x = pushed(0);
Cell xs = pushed(1);
Cell temp = evalWithNoError(x);
if (nonNull(temp))
updapRoot(consOsq,
printBadRedex(temp,
lprint(nameLPrint,xs,ss)));
else if (isChar(whnfHead) && whnfArgs==0)
updapRoot(consDQuote,
printSChar(charOf(whnfHead),
lprint(nameSPrint,xs,ss)));
else
updapRoot(consOsq,
print(namePrint,MIN_PREC,x,
lprint(nameLPrint,xs,ss)));
}
static Void local startNList(root,ss) /* start printing unevaluated list */
StackPtr root;
Cell ss; {
Cell x = pushed(0);
Cell xs = pushed(1);
unwind(x);
if (isChar(whnfHead) && whnfArgs==0)
updapRoot(consDQuote,
printSChar(charOf(whnfHead),
lprint(nameNSPrint,xs,ss)));
else
updapRoot(consOsq,
print(nameNPrint,MIN_PREC,x,
lprint(nameNLPrint,xs,ss)));
}
primFun(primLPrint) { /* evaluate and print list */
Cell e = primArg(2);
Cell ss = primArg(1);
Cell temp = evalWithNoError(e);
if (nonNull(temp))
updateRoot(printString("] ++ ",printBadRedex(temp,ss)));
else if (whnfHead==nameCons && whnfArgs==2)
updapRoot(consComma,
ap(consSpace,
print(namePrint,MIN_PREC,pushed(0),
lprint(nameLPrint,pushed(1),ss))));
else if (whnfHead==nameNil && whnfArgs==0)
updapRoot(consCsq,ss);
else
updateRoot(printString("] ++ ",printBadRedex(e,ss)));
}
primFun(primNLPrint) { /* print list without evaluation */
Cell e = primArg(2);
Cell ss = primArg(1);
unwind(e);
if (whnfHead==nameCons && whnfArgs==2)
updapRoot(consComma,
ap(consSpace,
print(nameNPrint,MIN_PREC,pushed(0),
lprint(nameNLPrint,pushed(1),ss))));
else if (whnfHead==nameNil && whnfArgs==0)
updapRoot(consCsq,ss);
else
updateRoot(printString("] ++ ",print(nameNPrint,FUN_PREC-1,e,ss)));
}
primFun(primSPrint) { /* evaluate and print string */
Cell e = primArg(2);
Cell ss = primArg(1);
Cell temp = evalWithNoError(e);
if (nonNull(temp))
updateRoot(printString("\" ++ ",printBadRedex(temp,ss)));
else if (whnfHead==nameCons && whnfArgs==2) {
Cell x = pushed(0);
Cell xs = pushed(1);
temp = evalWithNoError(x);
if (nonNull(temp))
updateRoot(printString("\" ++ [",
printBadRedex(temp,
lprint(nameLPrint,xs,ss))));
else if (isChar(whnfHead) && whnfArgs==0)
updateRoot(printSChar(charOf(whnfHead),
lprint(nameSPrint,xs,ss)));
else
updateRoot(printString("\" ++ [",
printBadRedex(x,
lprint(nameLPrint,xs,ss))));
}
else if (whnfHead==nameNil && whnfArgs==0)
updapRoot(consDQuote,ss);
else
updateRoot(printString("\" ++ ",printBadRedex(e,ss)));
}
primFun(primNSPrint) { /* print string without eval */
Cell e = primArg(2);
Cell ss = primArg(1);
unwind(e);
if (whnfHead==nameCons && whnfArgs==2) {
Cell x = pushed(0);
Cell xs = pushed(1);
unwind(x);
if (isChar(whnfHead) && whnfArgs==0)
updateRoot(printSChar(charOf(whnfHead),
lprint(nameNSPrint,xs,ss)));
else
updateRoot(printString("\" ++ [",
print(nameNPrint,MIN_PREC,x,
lprint(nameNLPrint,xs,ss))));
}
else if (whnfHead==nameNil && whnfArgs==0)
updapRoot(consDQuote,ss);
else
updateRoot(printString("\" ++ ",print(nameNPrint,FUN_PREC-1,e,ss)));
}
/* --------------------------------------------------------------------------
* Auxiliary functions for printer(s):
* ------------------------------------------------------------------------*/
static Cell local textAsVar(t,ss) /* reverse t as function symbol */
Text t; /* onto output ss */
Cell ss; {
String s = textToStr(t);
if ((isascii(s[0]) && isalpha(s[0])) || s[0]=='_' || strcmp(s,"[]")==0)
return stringOutput(s,ss);
else
return ap(consClose,stringOutput(s,ap(consOpen,ss)));
}
static Cell local textAsOp(t,ss) /* reverse t as op. symbol onto ss */
Text t;
Cell ss; {
String s = textToStr(t);
if (isascii(s[0]) && isalpha(s[0]))
return ap(consBack,stringOutput(s,ap(consBack,ss)));
else
return stringOutput(s,ss);
}
static Cell local stringOutput(s,ss) /* reverse string s onto output ss */
String s;
Cell ss; {
while (*s)
ss = ap(consChar(*s++),ss);
return ss;
}
static Cell local printBadRedex(rx,rs) /* Produce expression to print bad */
Cell rx, rs; { /* redex and then print rest ... */
return ap(consObrace,
print(nameNPrint,MIN_PREC,rx,
ap(consCbrace,
rs)));
}
static Cell consCharArray[NUM_CHARS];
Cell consChar(c) /* return application (:) c */
Char c; {
if (c<0)
c += NUM_CHARS;
return consCharArray[c];
}
Void abandon(what,rx) /* abandon computation */
String what;
Cell rx; {
outputString(errorStream,
revOnto(stringOutput("\nAborting ",NIL),
revOnto(stringOutput(what,NIL),
revOnto(stringOutput(": ",NIL),
printDBadRedex(rx,nameNil)))),TRUE);
errAbort();
}
/* --------------------------------------------------------------------------
* Evaluate name, obtaining a C string from a Gofer string:
* ------------------------------------------------------------------------*/
static String local evalName(es) /* evaluate es :: [Char] and save */
Cell es; { /* in char array... return ptr to */
static char buffer[FILENAME_MAX+1]; /* string or 0, if error occurs */
Int pos = 0;
StackPtr saveSp = sp;
while (isNull(evalWithNoError(es)))
if (whnfHead==nameCons && whnfArgs==2) {
Cell e = pop(); /* avoid leaving anything on stack */
es = pop();
if (isNull(evalWithNoError(e))
&& isChar(whnfHead) && whnfArgs==0
&& pos<FILENAME_MAX)
buffer[pos++] = charOf(whnfHead);
else
break;
}
else if (whnfHead==nameNil && whnfArgs==0) {
buffer[pos] = '\0';
return buffer;
}
else
break;
sp = saveSp; /* stack pointer must be the same */
return 0; /* as it was on entry */
}
/* --------------------------------------------------------------------------
* Dialogue based input/output:
*
* N.B. take care when modifying this code - it is rather delicate and even
* the simplest of changes might create a nasty space leak... you have been
* warned (please let me know if you think there already is a space leak!).
* ------------------------------------------------------------------------*/
static Name nameReadFile, nameWriteFile, nameAppendFile;
static Name nameReadChan, nameAppendChan, nameEcho;
static Name nameSuccess, nameStr, nameFailure;
static Name nameWriteError, nameReadError, nameSearchError;
static Name nameFormatError, nameOtherError;
static Bool echoChanged; /* TRUE => echo changed in dialogue*/
static Bool stdinUsed; /* TRUE => ReadChan stdin has been */
/* seen in dialogue */
static FILE *writingFile = 0; /* points to file open for writing */
Void dialogue(prog) /* carry out dialogue ... */
Cell prog; { /* :: Dialog=[Response]->[Request] */
static String ioerr = "Attempt to read response before request complete";
Cell tooStrict = mkStr(findText(ioerr));
Cell resps = prog = ap(prog,NIL);
Cell temp;
echoChanged = FALSE;
stdinUsed = FALSE;
for (;;) { /* Keep Responding to Requests */
resps = snd(resps) = ap(nameError,tooStrict);
clearStack();
if (nonNull(temp=evalWithNoError(prog)))
abandonDialogue(temp);
else if (whnfHead==nameCons && whnfArgs==2) {
if (nonNull(temp=evalWithNoError(pushed(0))))
abandonDialogue(temp);
prog = pushed(1+whnfArgs);
if (whnfHead==nameReadFile && whnfArgs==1)
fst(resps) = ap(nameCons,readFile());
else if (whnfHead==nameWriteFile && whnfArgs==2)
fst(resps) = ap(nameCons,writeFile());
else if (whnfHead==nameAppendFile && whnfArgs==2)
fst(resps) = ap(nameCons,appendFile());
else if (whnfHead==nameReadChan && whnfArgs==1)
fst(resps) = ap(nameCons,readChan());
else if (whnfHead==nameAppendChan && whnfArgs==2)
fst(resps) = ap(nameCons,appendChan());
else if (whnfHead==nameEcho && whnfArgs==1)
fst(resps) = ap(nameCons,echo());
else
abandonDialogue(pushed(whnfArgs));
}
else if (whnfHead==nameNil && whnfArgs==0) {
normalTerminal();
return;
}
else
internal("Type error during Dialogue");
}
}
static Void local abandonDialogue(rx) /* abandon dialogue after failure */
Cell rx; { /* to reduce redex rx */
abandon("Dialogue",rx);
}
static Cell local printDBadRedex(rx,rs) /* Produce expression for bad redex*/
Cell rx, rs; { /* within a Dialogue, with special */
if (isAp(rx) && fun(rx)==nameError) /* handling of {error str} redexes */
return arg(rx);
else
return printBadRedex(rx,rs);
}
static Cell local readFile() { /* repond to ReadFile request */
String s = evalName(pushed(0)); /* pushed(0) = file name string */
Cell temp = NIL; /* pushed(1) = ReadFile request */
/* pushed(2) = rest of program */
if (!s) /* problem with filename? */
abandonDialogue(pushed(1));
if (access(s,0)!=0) /* can't find file */
return ap(nameFailure,ap(nameSearchError,pushed(0)));
if (isNull(temp = openFile(s))) /* can't open file */
return ap(nameFailure,ap(nameReadError,pushed(0)));
return ap(nameStr,temp); /* otherwise we got a file! */
}
static Cell local writeFile() { /* respond to WriteFile req. */
String s = evalName(pushed(0)); /* pushed(0) = file name string */
FILE *fp; /* pushed(1) = output string */
Cell temp; /* pushed(2) = output request */
/* pushed(3) = rest of program */
if (!s) /* problem with filename? */
abandonDialogue(pushed(2));
if ((fp=fopen(s,FOPEN_WRITE))==0) /* problem with output file? */
return ap(nameFailure,ap(nameWriteError,pushed(0)));
writingFile = fp;
temp = outputString(fp,pushed(1),FALSE);
fclose(fp);
writingFile = 0;
if (nonNull(temp))
return ap(nameFailure,ap(nameWriteError,temp));
else
return nameSuccess;
}
static Cell local appendFile() { /* respond to AppendFile req. */
String s = evalName(pushed(0)); /* pushed(0) = file name string */
FILE *fp; /* pushed(1) = output string */
Cell temp; /* pushed(2) = output request */
/* pushed(3) = rest of program */
if (!s) /* problem with filename? */
abandonDialogue(pushed(2));
if (access(s,0)!=0) /* can't find file? */
return ap(nameFailure,ap(nameSearchError,pushed(0)));
if ((fp=fopen(s,FOPEN_APPEND))==0) /* problem with output file? */
return ap(nameFailure,ap(nameWriteError,pushed(0)));
writingFile = fp;
temp = outputString(fp,pushed(1),FALSE);
fclose(fp);
writingFile = 0;
if (nonNull(temp))
return ap(nameFailure,ap(nameWriteError,temp));
else
return nameSuccess;
}
static Cell local readChan() { /* respond to readChan req. */
String s = evalName(pushed(0)); /* pushed(0) = channel name string */
/* pushed(1) = output request */
/* pushed(2) = rest of program */
if (!s) /* problem with filename? */
abandonDialogue(pushed(1));
if (strcmp(s,"stdin")!=0) /* only valid channel == stdin */
return ap(nameFailure,ap(nameSearchError,pushed(0)));
if (stdinUsed) /* can't reuse stdin channel! */
return ap(nameFailure,ap(nameReadError,pushed(0)));
stdinUsed = TRUE;
return ap(nameStr,ap(nameInput,UNIT));
}
static Cell local appendChan() { /* respond to AppendChannel req. */
String s = evalName(pushed(0)); /* pushed(0) = channel name string */
FILE *fp; /* pushed(1) = output string */
Cell temp; /* pushed(2) = output request */
/* pushed(3) = rest of program */
if (!s) /* problem with filename? */
abandonDialogue(pushed(2));
if ((fp = validOutChannel(s))==0) /* problem with output channel? */
return ap(nameFailure,ap(nameSearchError,pushed(0)));
if (nonNull(temp=outputString(fp,pushed(1),FALSE)))
return ap(nameFailure,ap(nameWriteError,temp));
else
return nameSuccess;
}
static FILE *local validOutChannel(s) /* return FILE * for valid output */
String s; { /* channel name or 0 otherwise... */
if (strcmp(s,"stdout")==0)
return stdout;
if (strcmp(s,"stderr")==0)
return stderr;
if (strcmp(s,"stdecho")==0) /* in Gofer, stdecho==stdout */
return stdout;
return 0;
}
static Cell local echo() { /* respond to Echo request */
/* pushed(0) = boolean echo status */
/* pushed(1) = echo request */
/* pushed(2) = rest of program */
static String inUse = "stdin already in use";
static String repeat = "repeated Echo request";
if (isNull(evalWithNoError(pushed(0)))) {
if (stdinUsed)
return ap(nameFailure,ap(nameOtherError,mkStr(findText(inUse))));
if (echoChanged)
return ap(nameFailure,ap(nameOtherError,mkStr(findText(repeat))));
if (whnfHead==nameFalse && whnfArgs==0) {
echoChanged = TRUE;
noechoTerminal();
return nameSuccess;
}
if (whnfHead==nameTrue && whnfArgs==0) {
echoChanged = TRUE;
return nameSuccess;
}
}
abandonDialogue(pushed(1));
return NIL;/*NOTREACHED*/
}
primFun(primInput) { /* read single character from stdin*/
Int c = readTerminalChar();
if (c==EOF || c<0 || c>=NUM_CHARS) {
clearerr(stdin);
updateRoot(nameNil);
}
else
updapRoot(consChar(c),ap(nameInput,UNIT));
}
/* --------------------------------------------------------------------------
* Top-level printing mechanism:
* ------------------------------------------------------------------------*/
Cell outputString(fp,cs,noDialogue) /* Evaluate string cs and print */
FILE *fp; /* on specified output stream fp */
Cell cs;
Bool noDialogue; { /* TRUE => not runnning Dialogue */
Cell temp;
for (;;) { /* keep reducing and printing head */
clearStack(); /* character */
temp = evalWithNoError(cs);
if (nonNull(temp))
if (noDialogue)
cs = printBadRedex(temp,nameNil);
else
return printDBadRedex(temp,nameNil);
else if (whnfHead==nameCons && whnfArgs==2) {
Cell c = pushed(0);
cs = pushed(1);
if (nonNull(temp=evalWithNoError(c)))
if (noDialogue)
cs = printBadRedex(temp,cs);
else
return printDBadRedex(temp,cs);
else if (isChar(whnfHead) && whnfArgs==0) {
fputc(charOf(whnfHead),fp);
fflush(fp);
}
else
break;
}
else if (whnfHead==nameNil && whnfArgs==0)
return NIL;
else
break;
}
internal("runtime type error");
return nameNil;/*NOTREACHED*/
}
/* --------------------------------------------------------------------------
* Built-in control:
* ------------------------------------------------------------------------*/
Void builtIn(what)
Int what; {
Int i;
switch (what) {
case RESET : if (writingFile) {
fclose(writingFile);
writingFile = 0;
}
break;
case MARK : for (i=0; i<NUM_CHARS; ++i)
mark(consCharArray[i]);
break;
case INSTALL : for (i=0; i<NUM_CHARS; ++i)
consCharArray[i] = ap(nameCons,mkChar(i));
consOpen = consCharArray['('];
consSpace = consCharArray[' '];
consComma = consCharArray[','];
consClose = consCharArray[')'];
consObrace = consCharArray['{'];
consCbrace = consCharArray['}'];
consOsq = consCharArray['['];
consCsq = consCharArray[']'];
consBack = consCharArray['`'];
consMinus = consCharArray['-'];
consQuote = consCharArray['\''];
consDQuote = consCharArray['\"'];
#define pFun(s,a,t,i) addPrim(newName(findText(s)),a,t,i)
nameFatbar = pFun("_FATBAR",2,NIL,primFatbar);
nameFail = pFun("_FAIL",0,NIL,primFail);
nameIf = pFun("_IF",3,NIL,primIf);
nameSel = pFun("_SEL",3,NIL,primSel);
nameMinus = pFun("_minus",2,NIL,primMinusInt);
nameDivide = pFun("_divide",2,NIL,primDivInt);
nameUndefMem = pFun("undefined_member",1,NIL,
primUndefMem);
namePrimCmp = pFun("_compare",1,NIL,primCmp);
namePrint = pFun("_print",3,NIL,primPrint);
nameNPrint = pFun("_nprint",3,NIL,primNPrint);
nameLPrint = pFun("_lprint",2,NIL,primLPrint);
nameNLPrint = pFun("_nlprint",2,NIL,primNLPrint);
nameSPrint = pFun("_sprint",2,NIL,primSPrint);
nameNSPrint = pFun("_nsprint",2,NIL,primNSPrint);
nameInput = pFun("_input",1,NIL,primInput);
#undef pFun
#define predef(nm,str) nm=newName(findText(str)); name(nm).defn=PREDEFINED
predef(nameReadFile, "ReadFile");
predef(nameWriteFile, "WriteFile");
predef(nameAppendFile, "AppendFile");
predef(nameReadChan, "ReadChan");
predef(nameAppendChan, "AppendChan");
predef(nameEcho, "Echo");
predef(nameSuccess, "Success");
predef(nameStr, "Str");
predef(nameFailure, "Failure");
predef(nameWriteError, "WriteError");
predef(nameReadError, "ReadError");
predef(nameSearchError, "SearchError");
predef(nameFormatError, "FormatError");
predef(nameAnd, "&&");
predef(nameOr, "||");
predef(nameError, "error");
#undef predef
break;
}
}
/*-------------------------------------------------------------------------*/